package cn.texous.demo.dzs.filter;

import cn.texous.util.commons.constant.Result;
import cn.texous.util.commons.constant.ResultCode;
import cn.texous.util.commons.util.GsonUtils;
import cn.texous.util.commons.util.StringUtils;
import cn.texous.demo.dzs.client.AuthorClient;
import cn.texous.demo.dzs.util.HttpRequestUtils;
import cn.texous.demo.dzs.util.PathUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * insert description here
 *
 * @author Showa.L
 * @since 2019/7/16 17:15
 */
@Slf4j
@Component
public class MyAuthorizationFilter extends ZuulFilter {

    private static final ObjectMapper OM = new ObjectMapper();

    @Autowired
    private AuthorClient authorClient;

    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();

        String uri = request.getRequestURI();
        GsonUtils.prettyInfoPrint(String.format("接收到请求：%s", uri));

        // 判断是否为登录操作
        if (isLoginUri(uri)) {
            // 登陆
            Object data = authorClient.login(request);
            return completeFilter(ctx, data);
        }

        // 判断是否是不需要鉴权的路径
        if (isNotAuthUri(uri)) {
            return null;
        }

        if (isCheckTokenUri(uri)) {
            // 判断access_token 是否有效
            boolean effective = effectiveAccessToken(request);
            return completeFilter(ctx, Result.ok(effective));
        }

        // 发起路由鉴权
        Result data = authorClient.authUri(request);
        // 鉴权成功则继续访问
        if (data != null && ResultCode.SUCCESS.getCode() == data.getCode())
            return null;

        log.info("用户鉴权失败：{}", GsonUtils.toJson(data));
        if (effectiveAccessToken(request))
            data = Result.out(ResultCode.INSUFFICIENT_PERMISSIONS);
        else
            data = Result.out(ResultCode.UNAUTHORIZED);
        return completeFilter(ctx, data);
    }

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return -200;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    private boolean effectiveAccessToken(HttpServletRequest request) {
        String accessToken = HttpRequestUtils.getAccessToken(request);
        if (StringUtils.isTrimEmpty(accessToken))
            return false;
        return authorClient.effectiveAccessToken(accessToken);
    }

    private boolean isCheckTokenUri(String uri) {
        return PathUtils.isCheckTokenUri(uri);
    }

    private boolean isLoginUri(String uri) {
        return PathUtils.isLoginUri(uri);
    }

    private boolean isNotAuthUri(String uri) {
        return PathUtils.isNotAuthUri(uri);
    }

    private Object completeFilter(RequestContext context, Object data) {
        context.getResponse().setHeader("Content-Type",
                MediaType.APPLICATION_JSON_UTF8_VALUE);
        context.setSendZuulResponse(false);
        context.setResponseStatusCode(ResultCode.SUCCESS.getCode());
        context.setResponseBody(getDataAsgeString(data));
        return null;
    }

    private String getDataAsgeString(Object data) {
        try {
            return OM.writeValueAsString(data);
        } catch (Exception e) {
            log.error("转换 Object - Bytes 失败", e);
        }
        return GsonUtils.toJson(Result.out(ResultCode.FAIL));
    }

}
